010 Editor v8.0.1_x32分析以及注册机制作

环境以及工具

Window7_x32

010 Editor v8.0.1_x32

OD

VS2017

第一步 找到判断注册结果的关键跳转和关键函数

使用OD打开010editor,进入到注册界面,先尝试输入随意的ID和Key,获取弹出的提示信息字符串

尝试在OD中搜索如下字符 “Invalid name or password.”,搜索结果如下

发现存在大量提示信息,我们在其中找到注册成功的提示信息,(上图红框:感谢购买010editor),双击查看反汇编窗口,见下图。

往上查看判断注册成功的关键跳转

我们发现地址为00DD5926处跳转JNZ 010Edito.00DD5A58应该为关键跳转,下方可以找到输出字符串”Password accepted. This ….”, 而其跳转地址处汇编代码为输出”Password accepted….”

(010editor使用QT界面库编写 ,我们可以猜测出push字符串随后的函数应为输出字符串)

回到关键跳转00DD5926处,判断密码为正确的条件为EDI = 0xDB,而EDI的值是EAX给的,而EAX为函数010Edito.00409C9B的返回值,这个函数可能为验证Key的关键函数,而我们动态调试发现有跳转直接跳转到cmp edi,0xdb。

同样为函数010Edito.00409C9B,现在可以认为这是关键函数,此时EDI的值为0x177,为了验证此跳转为关键跳转,我们把EDI的值修改为0xDB。

之后F9运行

验证成功!接下来我们进入函数分析。

第二步 分析关键函数1(返回DB为注册成功)

函数010Edito.00409C9B,参数情况为:

arg1 = 0x9 ;

arg2 = 0x4389;

从下往上看,找到需要的0xDB,而跳转条件是eax = 0x2D, 为函数010Edito.0040A826的返回值。

###第三步 分析关键函数2(返回2D为注册成功)

进入函数,该函数作用为将key取出,放在在局部变量数组中,数组起始地址为ebx-24

1
2
3
4
5
6
7
8
9
10
11
> key[0 ]	= [ebx-24]=0x12
> key[1 ] = [ebx-23]=0x34
> key[2 ] = [ebx-22]=0x56
> key[3 ] = [ebx-21]=0x78
> key[4 ] = [ebx-20]=0x90
> key[5 ] = [ebx-1F]=0x12
> key[6 ] = [ebx-1E]=0x34
> key[7 ] = [ebx-1D]=0x56
> key[8 ] = [ebx-1C]=0x78
> key[9 ] = [ebx-1B]=0x90
>

密钥数组对应如上,该处汇编代码如下,当KEY[3] == 0x9C时

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
> 013BDC5D   .  8A5D DF       MOV BL,BYTE PTR SS:[EBP-0x21]    ;  key[3]
> 013BDC60 . 8A7D E1 MOV BH,BYTE PTR SS:[EBP-0x1F] ; key[5]
> 013BDC63 . 80FB 9C CMP BL,0x9C ; 是否等于0x9c
> 013BDC66 . 75 70 JNZ SHORT 010Edito.013BDCD8 ; 跳转到是否等于FC
> 013BDC68 . 8A45 DC MOV AL,BYTE PTR SS:[EBP-0x24] ; key[0]
> 013BDC6B . 3245 E2 XOR AL,BYTE PTR SS:[EBP-0x1E] ; key[0]^key[6]
> 013BDC6E . 8845 E8 MOV BYTE PTR SS:[EBP-0x18],AL ;
> 013BDC71 . 8A45 DD MOV AL,BYTE PTR SS:[EBP-0x23] ; key[1]
> 013BDC74 . 3245 E3 XOR AL,BYTE PTR SS:[EBP-0x1D] ; key[1]^key[7]
> 013BDC77 . FF75 E8 PUSH DWORD PTR SS:[EBP-0x18]
> 013BDC7A . 0FB6C8 MOVZX ECX,AL
> 013BDC7D . B8 00010000 MOV EAX,0x100
> 013BDC82 . 66:0FAFC8 IMUL CX,AX ; (key[1]^key[7])*0x100
> 013BDC86 . 8A45 DE MOV AL,BYTE PTR SS:[EBP-0x22] ; key[2]
> 013BDC89 . 32C7 XOR AL,BH ; key[2]^key[5]
> 013BDC8B . 0FB6C0 MOVZX EAX,AL
> 013BDC8E . 66:03C8 ADD CX,AX
> ;cx = (key[1]^key[7])*0x100 + key[2]^key[5]
> 013BDC91 . 0FB7F1 MOVZX ESI,CX
> 013BDC94 . E8 AB9904FF CALL 010Edito.00407644
> 013BD0B0 /> \55 PUSH EBP
> 013BD0B1 |. 8BEC MOV EBP,ESP
> 013BD0B3 |. 8B45 08 MOV EAX,[ARG.1]
> ; eax = key[0]^key[6]
> 013BD0B6 |. 34 18 XOR AL,0x18
> ; al = key[0]^key[6]^0x18
> 013BD0B8 |. 04 3D ADD AL,0x3D
> ; al = key[0]^key[6]^0x18 + 0x3D
> 013BD0BA |. 34 A7 XOR AL,0xA7
> ; al =(key[0]^key[6]^0x18+0x3D)^0xA7
> 013BD0BC |. 5D POP EBP
> 013BD0BD \. C3 RETN
>
> 013BDC99 . 0FB6C0 MOVZX EAX,AL
> 013BDC9C . 56 PUSH ESI
> ; esi = (key[1]^key[7])*0x100 + key[2]^key[5]
> 013BDC9D . 8947 1C MOV DWORD PTR DS:[EDI+0x1C],EAX
> 013BDCA0 . E8 23A704FF CALL 010Edito.004083C8
> 013BD020 /> \55 PUSH EBP
> 013BD021 |. 8BEC MOV EBP,ESP
> 013BD023 |. 8B45 08 MOV EAX,[ARG.1]
> ;eax=(key[1]^key[7])*100+key[2]^key[5]
> 013BD026 |. B9 0B000000 MOV ECX,0xB
> ; ecx = 0xB
> 013BD02B |. 35 92780000 XOR EAX,0x7892
> ;eax=((key[1]^key[7])*0x100+key[2]^key[5])^0x7892
> 013BD030 |. 05 304D0000 ADD EAX,0x4D30
> ;eax=((key[1]^key[7])*0x100+key[2]^key[5])^0x7892 + 0x4D30
> 013BD035 |. 35 21340000 XOR EAX,0x3421
> ;eax=(((key[1]^key[7])*0x100+key[2]^key[5])^0x7892 + 0x4D30)^0x3421
> 013BD03A |. 0FB7C0 MOVZX EAX,AX
> 013BD03D |. 99 CDQ
> 013BD03E |. F7F9 IDIV ECX
> ;eax=(((key[1]^key[7])*0x100+key[2]^key[5])^0x7892 + 0x4D30)^0x3421/0xB
> 013BD040 |. 85D2 TEST EDX,EDX ;eax/ecx的余数是否为0
> 013BD042 |. 74 02 JE SHORT 010Edito.013BD046 ;如果余数不为0,清零eax
> 013BD044 |. 33C0 XOR EAX,EAX
> 013BD046 |> 5D POP EBP
> 013BD047 \. C3 RETN
>
> 013BDCA5 . 8B4F 1C MOV ECX,DWORD PTR DS:[EDI+0x1C]
> ; ecx = (key[0]^key[6]^0x18+0x3D)^0xA7
> 013BDCA8 . 83C4 08 ADD ESP,0x8
> 013BDCAB . 0FB7C0 MOVZX EAX,AX
> ;eax=(((key[1]^key[7])*100+key[2]^key[5])^0x7892 + 0x4D30)^0x3421
> 013BDCAE . 8947 20 MOV DWORD PTR DS:[EDI+0x20],EAX
> ;[EDI+0x20] =(((key[1]^key[7])*100+key[2]^key[5])^0x7892 + 0x4D30)^0x3421/0xB
> 013BDCB1 . 85C9 TEST ECX,ECX
> 013BDCB3 . 0F84 BC010000 JE 010Edito.013BDE75 ;ecx = 0 则eax=E7返回,验证失败
> 013BDCB9 . 85C0 TEST EAX,EAX
> 013BDCBB . 0F84 B4010000 JE 010Edito.013BDE75 ;eax = 0 则eax=E7返回,验证失败
> 013BDCC1 . 3D E8030000 CMP EAX,0x3E8
> 013BDCC6 . 0F87 A9010000 JA 010Edito.013BDE75 ;eax > 0x3E8 则eax=E7返回,验证失败
> 013BDCCC . 83F9 02 CMP ECX,0x2 ;ecx小于等于1时,借位cf=1,否则cf=0
> 013BDCCF . 1BF6 SBB ESI,ESI ; esi=esi-esi-CF=-cf
> 013BDCD1 . 23F1 AND ESI,ECX ;esi = esi & ecx
> 013BDCD3 . E9 B3000000 JMP 010Edito.013BDD8B ;0xAC分支也跳转到这里013BDD8B
>

当KEY[3] == 0x9C时,等换成C为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
> case 0x9C:
> {
> [EDI+0x1C] = (key[0]^key[6]^0x18+0x3D)^0xA7; //最后一步验证用到
> [EDI+0x20] =(((key[1]^key[7])*0x100+key[2]^key[5])^0x7892 + 0x4D30)^0x3421;
> eax=(((key[1]^key[7])*0x100+key[2]^key[5])^0x7892 + 0x4D30)^0x3421;
> ecx = (key[0]^key[6]^0x18+0x3D)^0xA7;
> cf = 0;
> if(eax % 0xB != 0)
> {
> eax = 0;
> }
> if(ecx == 0 || eax == 0 || eax > 0x3E8)
> {
> //验证失败
> return;
> }
> else
> {
>
> eax=(((key[1]^key[7])*0x100+key[2]^key[5])^0x7892 + 0x4D30)^0x3421/0xB;
> [EDI+0x20] = eax;
> if(ecx <= 1)
> {
> cf = 1;
> }
> esi = (0 - cf) & ecx; //cf=0 则 esi=0;
> }
> break;
> }
>

当KEY[3] == 0xFC时,所有跳转最终都不返回我们需要的0x2D ,跳过。

当KEY[3] == 0xAC时

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
> 013BDCFC   > \80FB AC       CMP BL,0xAC
> 013BDCFF . 0F85 70010000 JNZ 010Edito.013BDE75
> 013BDD05 . 8A45 DD MOV AL,BYTE PTR SS:[EBP-0x23] ; al = key[1]
> 013BDD08 . 3245 E3 XOR AL,BYTE PTR SS:[EBP-0x1D] ; al = key[1]^key[7]
> 013BDD0B . 0FB6C8 MOVZX ECX,AL ; ecx = key[1]^key[7]
> 013BDD0E . B8 00010000 MOV EAX,0x100
> 013BDD13 . 66:0FAFC8 IMUL CX,AX ; cx = (key[1]^key[7]) * 0x100
> 013BDD17 . 8A45 DE MOV AL,BYTE PTR SS:[EBP-0x22] ; al = key[2]
> 013BDD1A . 32C7 XOR AL,BH ; al = key[2]^key[5]
> 013BDD1C . C747 1C 02000>MOV DWORD PTR DS:[EDI+0x1C],0x2 ;[edi+0x1C] = 0x2
> 013BDD23 . 0FB6C0 MOVZX EAX,AL ; eax = key[2]^key[5]
> 013BDD26 . 66:03C8 ADD CX,AX ; cx = (key[1]^key[7]) * 0x100 + key[2]^key[5]
> 013BDD29 . 0FB7C1 MOVZX EAX,CX ; eax = (key[1]^key[7]) * 0x100 + key[2]^key[5]
> 013BDD2C . 50 PUSH EAX
> 013BDD2D . E8 96A604FF CALL 010Edito.004083C8
> 013BD020 /> \55 PUSH EBP
> 013BD021 |. 8BEC MOV EBP,ESP
> 013BD023 |. 8B45 08 MOV EAX,[ARG.1]
> 013BD026 |. B9 0B000000 MOV ECX,0xB
> 013BD02B |. 35 92780000 XOR EAX,0x7892 ; eax = ((key[1]^key[7]) * 0x100 + key[2]^key[5])^0x7892
> 013BD030 |. 05 304D0000 ADD EAX,0x4D30 ; eax = ((key[1]^key[7]) * 0x100 + key[2]^key[5])^0x7892 + 0x4D30
> 013BD035 |. 35 21340000 XOR EAX,0x3421 ; eax = (((key[1]^key[7]) * 0x100 + key[2]^key[5])^0x7892 + 0x4D30)^0x3421
> 013BD03A |. 0FB7C0 MOVZX EAX,AX
> 013BD03D |. 99 CDQ
> 013BD03E |. F7F9 IDIV ECX ; eax = ((((key[1]^key[7]) * 0x100 + key[2]^key[5])^0x7892 + 0x4D30)^0x3421)/0xB
> 013BD040 |. 85D2 TEST EDX,EDX ; 余数edx != 0 则,eax=0
> 013BD042 |. 74 02 JE SHORT 010Edito.013BD046
> 013BD044 |. 33C0 XOR EAX,EAX
> 013BD046 |> 5D POP EBP
> 013BD047 \. C3 RETN
>
> 013BDD32 . 0FB7C0 MOVZX EAX,AX
> 013BDD35 . 83C4 04 ADD ESP,0x4
> 013BDD38 . 8947 20 MOV DWORD PTR DS:[EDI+0x20],EAX
> 013BDD3B . 85C0 TEST EAX,EAX ; 检测上面的函数返回结果eax是否为0
> 013BDD3D . 0F84 32010000 JE 010Edito.013BDE75;eax=0跳转到返回0xE7,验证失败
> 013BDD43 . 3D E8030000 CMP EAX,0x3E8
> 013BDD48 . 0F87 27010000 JA 010Edito.013BDE75;eax大于0x3E8跳转到返回0xE7,验证失败
> 013BDD4E . 0FB655 E5 MOVZX EDX,BYTE PTR SS:[EBP-0x1B] ; edx = key[9]
> 013BDD52 . 0FB64D E0 MOVZX ECX,BYTE PTR SS:[EBP-0x20] ; ecx = key[4]
> 013BDD56 . 0FB6C7 MOVZX EAX,BH ; eax = key[5]
> 013BDD59 . 33D0 XOR EDX,EAX ; edx = key[9]^key[5]
> 013BDD5B . 0FB645 E4 MOVZX EAX,BYTE PTR SS:[EBP-0x1C] ; eax = key[8]
> 013BDD5F . 33C8 XOR ECX,EAX ; ecx = key[4]^key[8]
> 013BDD61 . C1E2 08 SHL EDX,0x8
> 013BDD64 . 0FB645 E2 MOVZX EAX,BYTE PTR SS:[EBP-0x1E] ; eax = key[6]
> 013BDD68 . 03D1 ADD EDX,ECX ; edx = ((key[9]^key[5])<<8) + key[4]^key[8]
> 013BDD6A . 0FB64D DC MOVZX ECX,BYTE PTR SS:[EBP-0x24] ; ecx = key[0]
> 013BDD6E . C1E2 08 SHL EDX,0x8 ; edx = (((key[9]^key[5]) << 8) + key[4]^key[8]) << 8
> 013BDD71 . 33C8 XOR ECX,EAX ; ecx = key[0]^key[6]
> 013BDD73 . 03D1 ADD EDX,ECX ; edx = ((((key[9]^key[5]) << 8) + key[4]^key[8]) << 8) + key[0]^key[6]
> 013BDD75 . 68 278C5B00 PUSH 010Edito.005B8C27 ; CCCCCCCC
> 013BDD7A . 52 PUSH EDX
> 013BDD7B . E8 0BCA04FF CALL 010Edito.0040A78B
> 013BCF90 /> \55 PUSH EBP
> 013BCF91 |. 8BEC MOV EBP,ESP
> 013BCF93 |. 8B4D 08 MOV ECX,[ARG.1] ; ecx = ((((key[9]^key[5]) << 8) + key[4]^key[8]) << 8) + key[0]^key[6]
> 013BCF96 |. B8 F1F0F0F0 MOV EAX,0xF0F0F0F1
> 013BCF9B |. 334D 0C XOR ECX,[ARG.2] ; ecx = (((((key[9]^key[5]) << 8) + key[4]^key[8]) << 8) + key[0]^key[6]) ^ 0x005B8C27
> 013BCF9E |. 81F1 78C02200 XOR ECX,0x22C078 ; ecx = ((((((key[9]^key[5]) << 8) + key[4]^key[8]) << 8) + key[0]^key[6]) ^ 0x005B8C27) ^ 0x22C078
> 013BCFA4 |. 81E9 75C10200 SUB ECX,0x2C175 ; ecx = ((((((key[9]^key[5]) << 8) + key[4]^key[8]) << 8) + key[0]^key[6]) ^ 0x005B8C27) ^ 0x22C078 - 0x2C175
> 013BCFAA |. 81F1 6731E5FF XOR ECX,0xFFE53167 ; ecx = (((((((key[9]^key[5]) << 8) + key[4]^key[8]) << 8) + key[0]^key[6]) ^ 0x005B8C27) ^ 0x22C078 - 0x2C175) ^ 0xFFE53167
> 013BCFB0 |. 81E1 FFFFFF00 AND ECX,0xFFFFFF ; ecx = ((((((((key[9]^key[5]) << 8) + key[4]^key[8]) << 8) + key[0]^key[6]) ^ 0x005B8C27) ^ 0x22C078 - 0x2C175) ^ 0xFFE53167) & 0xFFFFFF
> 013BCFB6 |. F7E1 MUL ECX ; eax = 0xF0F0F0F1 * ecx 结果高32位放在edx。 低32位放在eax
> 013BCFB8 |. C1EA 04 SHR EDX,0x4
> 013BCFBB |. 8BC2 MOV EAX,EDX
> 013BCFBD |. C1E0 04 SHL EAX,0x4
> 013BCFC0 |. 03C2 ADD EAX,EDX
> 013BCFC2 |. 2BC8 SUB ECX,EAX ;结果为0 则 zf=1
> 013BCFC4 |. B8 00000000 MOV EAX,0x0
> 013BCFC9 |. 0F44C2 CMOVE EAX,EDX ;当zf = 1时移动
> 013BCFCC |. 5D POP EBP
> 013BCFCD \. C3 RETN
>
>
> 013BDD80 . 83C4 08 ADD ESP,0x8
> 013BDD83 . 8945 F0 MOV DWORD PTR SS:[EBP-0x10],EAX
> 013BDD86 . 8947 34 MOV DWORD PTR DS:[EDI+0x34],EAX
> 013BDD89 . 8BF0 MOV ESI,EAX
> 013BDD8B > \8D45 EC LEA EAX,DWORD PTR SS:[EBP-0x14];0x9C分支也跳转到这里
>

转换成C代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
> case 0xAC:
> {
> eax = ((((key[1]^key[7]) * 0x100 + key[2]^key[5])^0x7892 + 0x4D30)^0x3421);
> ecx = ((((((((key[9]^key[5]) << 8) + key[4]^key[8]) << 8) + key[0]^key[6]) ^ 0x005B8C27) ^ 0x22C078 - 0x2C175) ^ 0xFFE53167) & 0xFFFFFF;
> if(eax % 0xB != 0)
> {
> eax = 0;
> return ; //跳转返回0x7E分支,验证失败
> }
> eax = ((((key[1]^key[7]) * 0x100 + key[2]^key[5])^0x7892 + 0x4D30)^0x3421)/0xB;
> eax = 0xF0F0F0F1 * ecx; // 结果高32位放在edx。 低32位放在eax
> edx = edx >> 4;
> eax = edx;
> eax = eax << 4;
> eax = eax + edx;
> ecx = ecx - eax;
> eax = 0;
> if(ecx==0
> {
> eax = edx;
> }
> [ebp-0x10] = eax; //最后一步验证用到
> [edi+0x34] = eax;
> esi = eax;
> break;
> }
>

分支0x9C、0xAC都将运行到此处

1
2
3
4
5
>013BDD8B   > \8D45 EC       LEA EAX,DWORD PTR SS:[EBP-0x14]
>013BDD8E . 50 PUSH EAX
>013BDD8F . 8D4F 04 LEA ECX,DWORD PTR DS:[EDI+0x4]
>013BDD92 . FF15 782BE702 CALL DWORD PTR DS:[<&Qt5Core.?toUtf8@QString@@QBE?AVQByteArr>; Qt5Core.?toUtf8@QString@@QBE?AVQByteArray@@XZ
>

不知道这段是干嘛,我们继续单步,到如上图所示,函数[<&Qt5Core.?data@QByteArray@@QAE>] 返回了用户名字符串,然后传入函数010Edito.00402E50,其再返回 一串类似哈希值的值,那么这个函数的作用应该为处理函数名称,进入分析。

第四步 分析用户名处理函数

根据mov esp, 0x10可知,用户名处理函数共有四个参数

参数1:用户名

参数2:当BL=0XFC时为1,否则为0,根据前面的分析可知,BL为Key[3]

参数3:esi,经上一个函数处理得到

参数4:[edi+0x20],经上一个函数处理得到

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
> 013BD120  /> \55            PUSH EBP
> 013BD121 |. 8BEC MOV EBP,ESP
> 013BD123 |. 83EC 10 SUB ESP,0x10
> 013BD126 |. 8B55 08 MOV EDX,[ARG.1]
> ;edx = 用户名pName
> 013BD129 |. 33C9 XOR ECX,ECX
> ;ecx = 0
> 013BD12B |. 56 PUSH ESI
> ;备份esi
> 013BD12C |. 8BF2 MOV ESI,EDX
> ;esi = 用户名pName
> 013BD12E |. 894D FC MOV [LOCAL.1],ECX
> ;[LOCAL.1] = 0
> 013BD131 |. 57 PUSH EDI
> ;备份EDI
> 013BD132 |. 8D7E 01 LEA EDI,DWORD PTR DS:[ESI+0x1]
> ;edi = 用户名地址 + 1,后面被esi减去求得长度
> 013BD135 |> 8A06 /MOV AL,BYTE PTR DS:[ESI]
> ;al = pName[0]
> 013BD137 |. 46 |INC ESI
> ;pName++
> 013BD138 |. 84C0 |TEST AL,AL
> 013BD13A |.^ 75 F9 \JNZ SHORT 010Edito.013BD135
> ;判断是否到达字符串结尾
> 013BD13C |. 2BF7 SUB ESI,EDI
> ;求得长度,ESI指向为用户名字符串结尾的'\0'
> 013BD13E |. 33FF XOR EDI,EDI
> 013BD140 |. 85F6 TEST ESI,ESI
> 013BD142 |. 0F8E F0000000 JLE 010Edito.013BD238
> ;检查长度是否不为0
> 013BD148 |. 53 PUSH EBX
> 013BD149 |. 8B5D 14 MOV EBX,[ARG.4]
> ;ebx = [ARG.4] = 传入的[edi+0x20]
> 013BD14C |. 894D F0 MOV [LOCAL.4],ECX ;置零
> 013BD14F |. 894D F4 MOV [LOCAL.3],ECX ;置零
> 013BD152 |. 8B4D 10 MOV ECX,[ARG.3]
> ;ecx = [ARG.3] = 传入的esi
> 013BD155 |. C1E3 04 SHL EBX,0x4
> 013BD158 |. 2B5D 14 SUB EBX,[ARG.4]
> ;ebx = ([ARG.4] *16) - [ARG.4]
> 013BD15B |. C1E1 04 SHL ECX,0x4
> 013BD15E |. 034D 10 ADD ECX,[ARG.3]
> ;ecx = ([ARG.3] *16) + [ARG.3]
> 013BD161 |. 894D F8 MOV [LOCAL.2],ECX
> ;[LOCAL.2] = ([ARG.3] << 4) + [ARG.3]
> 013BD164 |> 0FB60417 /MOVZX EAX,BYTE PTR DS:[EDI+EDX]
> 013BD168 |. 50 |PUSH EAX ; /c = B6
> 013BD169 |. FF15 9422E702 |CALL DWORD PTR DS:[<&MSVCR120.toupper>] ; \toupper 小写字母转换为大写字母
> 013BD16F |. 8BD0 |MOV EDX,EAX
> ;返回值复制给edx,大写字符
> 013BD171 |. 83C4 04 |ADD ESP,0x4
> 013BD174 |. 8B0C95 4841E6>|MOV ECX,DWORD PTR DS:[EDX*4+0x2E64148]
> ;将大写字母作为索引从数组0x2E64148中取内容
> ;为了方便,把数组0x2E64148称为nArray,故这里ecx = nArray[edx]
> 013BD17B |. 034D FC |ADD ECX,[LOCAL.1]
> ;ecx =nArray[大写字符] + [LOCAL.1] ,[LOCAL.1]最初为0
> 013BD17E |. 837D 0C 00 |CMP [ARG.2],0x0
> ;判断是哪种类型的注册
> 013BD182 |. 74 4A |JE SHORT 010Edito.013BD1CE
>
>
> ;注册类型1---------------------------------------------------------
> 013BD184 |. 8D42 0D |LEA EAX,DWORD PTR DS:[EDX+0xD]
> 013BD187 |. 25 FF000000 |AND EAX,0xFF
> ;eax = [大写字符+0xD] & 0xFF,这个值为数组下标,与0xFF可能说明数组最大个数为0xFF,即256个
> 013BD18C |. 330C85 4841E6>|XOR ECX,DWORD PTR DS:[EAX*4+0x2E64148]
> ;ecx = (nArray[大写字符] + [LOCAL.1]) ^ nArray[eax]
> 013BD193 |. 8D42 2F |LEA EAX,DWORD PTR DS:[EDX+0x2F]
> ;eax = [大写字符+0x2F]
> 013BD196 |. 25 FF000000 |AND EAX,0xFF
> ;eax = eax & 0xFF
> 013BD19B |. 0FAF0C85 4841>|IMUL ECX,DWORD PTR DS:[EAX*4+0x2E64148]
> ;ecx = ecx*nArray[eax]
> 013BD1A3 |. 8B45 F8 |MOV EAX,[LOCAL.2] ; 010Edito.01885E59
> ;eax = [LOCAL.2] = ([ARG.3] << 4) + [ARG.3]
> 013BD1A6 |. 0FB6C0 |MOVZX EAX,AL
> ;eax &= 0xFF
> 013BD1A9 |. 030C85 4841E6>|ADD ECX,DWORD PTR DS:[EAX*4+0x2E64148]
> ;ecx = ecx + nArray[eax]
> 013BD1B0 |. 0FB6C3 |MOVZX EAX,BL
> ;eax = ebx = ([ARG.4] << 4) - [ARG.4]
> 013BD1B3 |. 030C85 4841E6>|ADD ECX,DWORD PTR DS:[EAX*4+0x2E64148]
> ;ecx = ecx + nArray[eax]
> 013BD1BA |. 8B45 F4 |MOV EAX,[LOCAL.3]
> ;eax = [LOCAL.3]
> 013BD1BD |. 0FB6C0 |MOVZX EAX,AL
> 013BD1C0 |. 030C85 4841E6>|ADD ECX,DWORD PTR DS:[EAX*4+0x2E64148]
> ;ecx = ecx + nArray[eax]
> 013BD1C7 |. 8BC1 |MOV EAX,ECX
> ;eax = ecx
> 013BD1C9 |. 8945 FC |MOV [LOCAL.1],EAX
> ;[LOCAL.1] = eax
> 013BD1CC |. EB 48 |JMP SHORT 010Edito.013BD216
>
>
> ;注册类型0----------------------------------------------------------
> 013BD1CE |> 8D42 3F |LEA EAX,DWORD PTR DS:[EDX+0x3F];这里不同
> 013BD1D1 |. 25 FF000000 |AND EAX,0xFF
> 013BD1D6 |. 330C85 4841E6>|XOR ECX,DWORD PTR DS:[EAX*4+0x2E64148]
> 013BD1DD |. 8D42 17 |LEA EAX,DWORD PTR DS:[EDX+0x17];这里不同
> 013BD1E0 |. 25 FF000000 |AND EAX,0xFF
> 013BD1E5 |. 0FAF0C85 4841>|IMUL ECX,DWORD PTR DS:[EAX*4+0x2E64148]
> 013BD1ED |. 8B45 F8 |MOV EAX,[LOCAL.2] ; 010Edito.01885E59
> 013BD1F0 |. 0FB6C0 |MOVZX EAX,AL
> 013BD1F3 |. 030C85 4841E6>|ADD ECX,DWORD PTR DS:[EAX*4+0x2E64148]
> 013BD1FA |. 0FB6C3 |MOVZX EAX,BL
> 013BD1FD |. 030C85 4841E6>|ADD ECX,DWORD PTR DS:[EAX*4+0x2E64148]
> 013BD204 |. 8B45 F0 |MOV EAX,[LOCAL.4]
> ;eax = [LOCAL.4], 另一种注册类型这里为 [LOCAL.3]
> 013BD207 |. 0FB6C0 |MOVZX EAX,AL
> 013BD20A |. 030C85 4841E6>|ADD ECX,DWORD PTR DS:[EAX*4+0x2E64148]
> 013BD211 |. 8BC1 |MOV EAX,ECX
> 013BD213 |. 894D FC |MOV [LOCAL.1],ECX
>
>
>
> ;共通线----------------------------------------------------------------
> 013BD216 |> 8345 F4 13 |ADD [LOCAL.3],0x13
> ;[LOCAL.3] += 0x13
> 013BD21A |. 47 |INC EDI
> 013BD21B |. 8345 F8 09 |ADD [LOCAL.2],0x9
> ;[LOCAL.2] += 0x9
> 013BD21F |. 83C3 0D |ADD EBX,0xD
> ;EBX += 0xD
> 013BD222 |. 8345 F0 07 |ADD [LOCAL.4],0x7
> ;[LOCAL.4] += 0x7
> 013BD226 |. 8B55 08 |MOV EDX,[ARG.1]
> ; EDX = [ARG.1] = 用户名
> 013BD229 |. 3BFE |CMP EDI,ESI
> ;ESI指向为用户名字符串结尾的0, 判断EDI是否也到结尾,没有则继续循环计算
> 013BD22B |.^ 0F8C 33FFFFFF \JL 010Edito.013BD164
> 013BD231 |. 5B POP EBX ; 05661E08
> 013BD232 |. 5F POP EDI ; 05661E08
> 013BD233 |. 5E POP ESI ; 05661E08
> 013BD234 |. 8BE5 MOV ESP,EBP
> 013BD236 |. 5D POP EBP ; 05661E08
> 013BD237 |. C3 RETN
>
> ;用户名长度为0------------------------------------------------------
> 013BD238 |> 5F POP EDI ; 05661E08
> 013BD239 |. 8BC1 MOV EAX,ECX
> 013BD23B |. 5E POP ESI ; 05661E08
> 013BD23C |. 8BE5 MOV ESP,EBP
> 013BD23E |. 5D POP EBP ; 05661E08
> 013BD23F \. C3 RETN
>

转换成C语言

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
> arg_1 = pName;
> arg_2;
> arg_3 = ESI;
> arg_4 = [edi+0x20];
>
> DWORD LOCAL_1 = 0;
> DWORD LOCAL_2 = (arg_3 * 16) + arg_3
> DWORD LOCAL_3 = 0;
> DWORD LOCAL_4 = 0;
>
> ebx =(arg_4 * 16) - arg_4;
> char nArray[256]=
> {
> 39CB44B8, 23754F67, 5F017211, 3EBB24DA, 351707C6, 63F9774B, 17827288, 0FE74821, 5B5F670F, 48315AE8, 785B7769, 2B7A1547, 38D11292, 42A11B32, 35332244, 77437B60, 1EAB3B10, 53810000, 1D0212AE, 6F0377A8, 43C03092, 2D3C0A8E, 62950CBF, 30F06FFA, 34F710E0, 28F417FB, 350D2F95, 5A361D5A, 15CC060B, 0AFD13CC, 28603BCF, 3371066B, 30CD14E4, 175D3A67, 6DD66A13, 2D3409F9, 581E7B82, 76526B99, 5C8D5188, 2C857971, 15F51FC0, 68CC0D11, 49F55E5C, 275E4364, 2D1E0DBC, 4CEE7CE3, 32555840, 112E2E08, 6978065A, 72921406, 314578E7, 175621B7, 40771DBF, 3FC238D6, 4A31128A, 2DAD036E, 41A069D6, 25400192, 00DD4667, 6AFC1F4F, 571040CE, 62FE66DF, 41DB4B3E, 3582231F, 55F6079A, 1CA70644, 1B1643D2, 3F7228C9, 5F141070, 3E1474AB, 444B256E, 537050D9, 0F42094B, 2FD820E6, 778B2E5E, 71176D02, 7FEA7A69, 5BB54628, 19BA6C71, 39763A99, 178D54CD, 01246E88, 3313537E, 2B8E2D17, 2A3D10BE, 59D10582, 37A163DB, 30D6489A, 6A215C46, 0E1C7A76, 1FC760E7, 79B80C65, 27F459B4, 799A7326, 50BA1782, 2A116D5C, 63866E1B, 3F920E3C, 55023490, 55B56089, 2C391FD1, 2F8035C2, 64FD2B7A, 4CE8759A, 518504F0, 799501A8, 3F5B2CAD, 38E60160, 637641D8, 33352A42, 51A22C19, 085C5851, 032917AB, 2B770AC7, 30AC77B3, 2BEC1907, 035202D0, 0FA933D3, 61255DF3, 22AD06BF, 58B86971, 5FCA0DE5, 700D6456, 56A973DB, 5AB759FD, 330E0BE2, 5B3C0DDD, 495D3C60, 53BD59A6, 4C5E6D91, 49D9318D, 103D5079, 61CE42E3, 7ED5121D, 14E160ED, 212D4EF2, 270133F0, 62435A96, 1FA75E8B, 6F092FBE, 4A000D49, 57AE1C70, 004E2477, 561E7E72, 468C0033, 5DCC2402, 78507AC6, 58AF24C7, 0DF62D34, 358A4708, 3CFB1E11, 2B71451C, 77A75295, 56890721, 0FEF75F3, 120F24F1, 01990AE7, 339C4452, 27A15B8E, 0BA7276D, 60DC1B7B, 4F4B7F82, 67DB7007, 4F4A57D9, 621252E8, 20532CFC, 6A390306, 18800423, 19F3778A, 462316F0, 56AE0937, 43C2675C, 65CA45FD, 0D604FF2, 0BFD22CB, 3AFE643B, 3BF67FA6, 44623579, 184031F8, 32174F97, 4C6A092A, 5FB50261, 01650174, 33634AF1, 712D18F4, 6E997169, 5DAB7AFE, 7C2B2EE8, 6EDB75B4, 5F836FB6, 3C2A6DD6, 292D05C2, 052244DB, 149A5F4F, 5D486540, 331D15EA, 4F456920, 483A699F, 3B450F05, 3B207C6C, 749D70FE, 417461F6, 62B031F1, 2750577B, 29131533, 588C3808, 1AEF3456, 0F3C00EC, 7DA74742, 4B797A6C, 5EBB3287, 786558B8, 00ED4FF2, 6269691E, 24A2255F, 62C11F7E, 2F8A7DCD, 643B17FE, 778318B8, 253B60FE, 34BB63A3, 5B03214F, 5F1571F4, 1A316E9F, 7ACF2704, 28896838, 18614677, 1BF569EB, 0BA85EC9, 6ACA6B46, 1E43422A, 514D5F0E, 413E018C, 307626E9, 01ED1DFA, 49F46F5A, 461B642B, 7D7007F2, 13652657, 6B160BC5, 65E04849, 1F526E1C, 5A0251B6, 2BD73F69, 2DBF7ACD, 51E63E80, 5CF2670F, 21CD0A03, 5CFF0261, 33AE061E, 3BB6345F, 5D814A75, 257B5DF4, 0A5C2C5B, 16A45527, 16F23945
> };
>
> while(nNameLen)
> {
> pName[i]
> char cName = toupper(pName); //小写转大写
>
> //注册类型1
> if(key[3] != 0xFC)
> {
> LOCAL_1 = (nArray[cName]+LOCAL_1);
> LOCAL_1 ^= nArray[(cName+0xD)];
> LOCAL_1 *= nArray[(cName+0x2F)];
>
> LOCAL_1 += nArray[LOCAL_2];
> LOCAL_1 += nArray[ebx];
> LOCAL_1 += nArray[LOCAL_3];
> }
> //注册类型0,没有用到
> else if(key[3] == 0xFC)
> {
> LOCAL_1 = (nArray[cName]+LOCAL_1);
> LOCAL_1 ^= nArray[(cName+0x3F)];
> LOCAL_1 *= nArray[(cName+0x17)];
>
> LOCAL_1 += nArray[LOCAL_2];
> LOCAL_1 += nArray[ebx];
> LOCAL_1 += nArray[LOCAL_4];
> }
> LOCAL_3 += 0x13;
> nNameLen--;
> LOCAL_2 += 0x9;
> ebx += 0xD
> LOCAL_4 += 0x7;
> i++;
> }
> return LOCAL_1;
>

函数返回结果如上图。

第五步 处理计算结果

由上图分析可知,接下来将处理用户名函数的返回值多次右移比较,根据结果分发返回值,最终跳转到我们需要的返回值0x2D。代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
>013BDDB6   .  E8 955004FF   CALL 010Edito.00402E50			 ;  处理用户名的函数
>013BDDBB . 8BD0 MOV EDX,EAX
>013BDDBD . 83C4 10 ADD ESP,0x10 ; 意味着上面函数有四个参数
>013BDDC0 . 3855 E0 CMP BYTE PTR SS:[EBP-0x20],DL ; 比较key[4],返回值低8位
>013BDDC3 . 0F85 81000000 JNZ 010Edito.013BDE4A ; 跳转到返回0xE7,失败
>013BDDC9 . 8BCA MOV ECX,EDX
>013BDDCB . C1E9 08 SHR ECX,0x8 ; 右移0x8
>013BDDCE . 3AF9 CMP BH,CL ; key[5],cl
>013BDDD0 . 75 78 JNZ SHORT 010Edito.013BDE4A ; 跳转到返回0xE7,失败
>013BDDD2 . 8BCA MOV ECX,EDX
>013BDDD4 . C1E9 10 SHR ECX,0x10 ; 右移10位
>013BDDD7 . 384D E2 CMP BYTE PTR SS:[EBP-0x1E],CL ; key[6]
>013BDDDA . 75 6E JNZ SHORT 010Edito.013BDE4A ; 跳转到返回0xE7,失败
>013BDDDC . C1E8 18 SHR EAX,0x18 ; 右移0x18
>013BDDDF . 3845 E3 CMP BYTE PTR SS:[EBP-0x1D],AL ; key[7]
>013BDDE2 . 75 66 JNZ SHORT 010Edito.013BDE4A ; 跳转到返回0xE7,失败
>013BDDE4 . 80FB 9C CMP BL,0x9C ; Switch (cases 9C..FC)
>013BDDE7 . 75 0F JNZ SHORT 010Edito.013BDDF8
>013BDDE9 . 8B45 08 MOV EAX,DWORD PTR SS:[EBP+0x8] ; Case 9C of switch 013BDDE4
>013BDDEC . 3B47 1C CMP EAX,DWORD PTR DS:[EDI+0x1C] ; 小于等于
>013BDDEF . 76 52 JBE SHORT 010Edito.013BDE43 ; 跳转到返回0x2D,验证正确
>013BDDF1 . BE 4E000000 MOV ESI,0x4E
>013BDDF6 . EB 57 JMP SHORT 010Edito.013BDE4F ; 返回返回4E,验证失败
>013BDDF8 > 80FB FC CMP BL,0xFC
>013BDDFB . 75 2E JNZ SHORT 010Edito.013BDE2B ; FC分支得不到正确结果,跳过
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
>013BDE2B   >  80FB AC       CMP BL,0xAC
>013BDE2E . 75 1A JNZ SHORT 010Edito.013BDE4A
>013BDE30 . 8B45 F0 MOV EAX,DWORD PTR SS:[EBP-0x10] ; Case AC of switch 013BDDE4
>013BDE33 . 85C0 TEST EAX,EAX
>013BDE35 . 74 13 JE SHORT 010Edito.013BDE4A ; 跳转到验证错误
>013BDE37 . 3945 0C CMP DWORD PTR SS:[EBP+0xC],EAX
>013BDE3A . 76 07 JBE SHORT 010Edito.013BDE43 ; 跳转到返回0x2D,验证正确
>013BDE3C . BE 4E000000 MOV ESI,0x4E
>013BDE41 . EB 0C JMP SHORT 010Edito.013BDE4F
>013BDE43 > BE 2D000000 MOV ESI,0x2D ; 验证正确,返回0x2D!!!!
>013BDE48 . EB 05 JMP SHORT 010Edito.013BDE4F
>013BDE4A > BE E7000000 MOV ESI,0xE7 ; Default case of switch 013BDDE4
>013BDE4F > 8D4D EC LEA ECX,DWORD PTR SS:[EBP-0x14]
>013BDE52 . C745 FC FFFFF>MOV DWORD PTR SS:[EBP-0x4],-0x1
>013BDE59 . FF15 7C24E702 CALL DWORD PTR DS:[<&Qt5Core.??1Q>; Qt5Core.??1QByteArray@@QAE@XZ
>013BDE5F . 8BC6 MOV EAX,ESI
>013BDE61 . 8B4D F4 MOV ECX,DWORD PTR SS:[EBP-0xC]
>013BDE64 . 64:890D 00000>MOV DWORD PTR FS:[0],ECX
>013BDE6B . 59 POP ECX ; 0584FD48
>013BDE6C . 5F POP EDI ; 0584FD48
>013BDE6D . 5E POP ESI ; 0584FD48
>013BDE6E . 5B POP EBX ; 0584FD48
>013BDE6F . 8BE5 MOV ESP,EBP
>013BDE71 . 5D POP EBP ; 0584FD48
>013BDE72 . C2 0800 RETN 0x8
>

上述代码中,将返回值低八位和key[ n ]进行比较,每次比较完后右移八位,再次比较新数值的低八位。总共比较4次,正好将32位返回值全部比对完。

在第三步分析0x9C分支中已经得到 [EDI+0x1C] = ecx = (key[0]^key[6]^0x18+0x3D)^0xA7,

局部变量 [ EBP+0x8 ] = 9。

局部变量[ EBP - 0x10] 为第三步中分析AC分支返回eax得到,

1
2
> eax = ((((key[1]^key[7]) * 0x100 + key[2]^key[5])^0x7892 + 0x4D30)^0x3421)/0xB;
>

局部变量 [ EBP+0xC ] = 4389。

转换为C代码为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
>//将返回值看成为一个数组,nArray[4]
>if((nArray[0]==key[4]) &&
> (nArray[1]==key[5]) &&
> (nArray[2]==key[6]) &&
> (nArray[3]==key[7]))
> {
> if(key[3]==0x9C)
> {
> //[EDI+0x1C] = (key[0]^key[6]^0x18+0x3D)^0xA7;
> if(9 <= (key[0]^key[6]^0x18+0x3D)^0xA7))
> {
> return 0x2D; //验证成功
> }
> return 0x4E; //验证失败
> }
> else if(key[3]==0xFC)
> {
> return 0xE7; //验证失败
> }
> else if(key[3]=0xAC)
> {
> if([ebp - 10] >= 4389)
> {
> return 0x2D; //验证成功
> }
> return 0x4E; //验证失败
> }
> }
>

第六步 编写注册机

文章作者: yusakul
文章链接: http://yoursite.com/2018/06/25/010 Editor分析/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 梁言